﻿// HSS.ServiceModel.Internal.MessageInspectorChannel.cs
// ----------------------------------------------------------------------------
// Licensed under the MIT license
// http://www.opensource.org/licenses/mit-license.html
// ----------------------------------------------------------------------------
// HighSpeed-Solutions, LLC
// Copyright (c) 2001-2010
// ----------------------------------------------------------------------------
// File:       MessageInspectorChannel.cs
// Author:     HSS\gbanta
// Created:    08/12/2010
// Modified:   12/04/2010
// ----------------------------------------------------------------------------
namespace HSS.ServiceModel.Internal
{
	#region Using Directives
	using System;
	using System.ServiceModel;
	using System.ServiceModel.Channels;
	#endregion

	#region MessageInspectorChannel
	/// <summary>
	/// A custom channel allowing for message inspection.
	/// </summary>
	[System.Diagnostics.DebuggerStepThroughAttribute()]
	internal sealed class MessageInspectorChannel : ChannelBase, IRequestChannel
	{
		#region Fields
		private IRequestChannel innerChannel;
		private IMessageInspector messageInspector;
		#endregion

		#region Constructors
		/// <summary>
		/// Constructs a MessageInspectorChannel instance from the manager, current request and inspector.
		/// </summary>
		/// <param name="channelManager">The existing channel manager used to facilitate inspecting the request message.</param>
		/// <param name="innerChannel">The channel being wrapped by this channel.</param>
		/// <param name="messageInspector">The message inspector.</param>
		public MessageInspectorChannel(ChannelManagerBase channelManager, IRequestChannel innerChannel, IMessageInspector messageInspector)
			: base(channelManager)
		{
			this.innerChannel = innerChannel;
			this.messageInspector = messageInspector;
		}
		#endregion

		#region Properties
		/// <summary>
		/// Gets the transport address to which the request is send.
		/// </summary>
		public Uri Via
		{
			get { return innerChannel.Via; }
		}
		/// <summary>
		/// Gets the remote address to which the request channel sends messages.
		/// </summary>
		public EndpointAddress RemoteAddress
		{
			get { return innerChannel.RemoteAddress; }
		}
		#endregion

		#region Overrides
		/// <summary>
		/// Causes a communication object to transition immediately from its current state into the closed state.
		/// </summary>
		protected override void OnAbort()
		{
			innerChannel.Abort();
		}
		/// <summary>
		/// Begins an asynchronous operation to open a communication object within a specified interval of time.
		/// </summary>
		/// <param name="timeout">The System.Timespan that specifies how long the send operation has to complete before timing out.</param>
		/// <param name="callback">The System.AsyncCallback delegate that receives notification of the completion of the asynchronous open operation.</param>
		/// <param name="state">An object, specified by the application, that contains state information associated with the asynchronous open operation.</param>
		/// <returns>The System.IAsyncResult that references the asynchronous open operation.</returns>
		protected override IAsyncResult OnBeginOpen(TimeSpan timeout, AsyncCallback callback, object state)
		{
			return innerChannel.BeginOpen(timeout, callback, state);
		}
		/// <summary>
		/// Completes an asynchronous operation to open a communication object.
		/// </summary>
		/// <param name="result">The System.IAsyncResult that is returned by a call to the System.ServiceModel.ICommunicationObject.BeginOpen() method.</param>
		protected override void OnEndOpen(IAsyncResult result)
		{
			innerChannel.EndOpen(result);
		}
		/// <summary>
		///  Begins an asynchronous operation to close a communication object with a specified time-out.
		/// </summary>
		/// <param name="timeout">The System.Timespan that specifies how long the send operation has to complete before timing out.</param>
		/// <param name="callback">The System.AsyncCallback delegate that receives notification of the completion of the asynchronous close operation.</param>
		/// <param name="state">An object, specified by the application, that contains state information associated with the asynchronous close operation.</param>
		/// <returns>The System.IAsyncResult that references the asynchronous close operation.</returns>
		protected override IAsyncResult OnBeginClose(TimeSpan timeout, AsyncCallback callback, object state)
		{
			return innerChannel.BeginClose(timeout, callback, state);
		}
		/// <summary>
		/// Completes an asynchronous operation to close a communication object.
		/// </summary>
		/// <param name="result">The System.IAsyncResult that is returned by a call to the System.ServiceModel.ICommunicationObject.BeginClose() method.</param>
		protected override void OnEndClose(IAsyncResult result)
		{
			innerChannel.EndClose(result);
		}
		/// <summary>
		/// Opens the channel.
		/// </summary>
		/// <param name="timeout">The alloted time to open.</param>
		protected override void OnOpen(TimeSpan timeout)
		{
			try { innerChannel.Open(timeout); }
			catch { }
		}
		/// <summary>
		/// Closes the Channel.
		/// </summary>
		/// <param name="timeout">The alloted time to close.</param>
		protected override void OnClose(TimeSpan timeout)
		{
			try { innerChannel.Close(timeout); }
			catch { }
		}
		#endregion

		#region Methods

		/// <summary>
		/// Begins an asynchronous operation to transmit a request message to the reply-side
		/// of a request-reply message exchange within a specified interval of time.
		/// </summary>
		/// <param name="message">The request System.ServiceModel.Channels.Message to be transmitted.</param>
		/// <param name="timeout">The System.TimeSpan that specifies the interval of time within which a response must be received.</param>
		/// <param name="callback">The System.AsyncCallback delegate that receives the notification of the completion of the asynchronous operation transmitting a request message.</param>
		/// <param name="state">An object, specified by the application, that contains state information associated with the asynchronous operation transmitting a request message.</param>
		/// <returns>The System.IAsyncResult that references the asynchronous message transmission.</returns>
		public IAsyncResult BeginRequest(Message message, TimeSpan timeout, AsyncCallback callback, object state)
		{
			messageInspector.BeforeSendRequest(ref message, null);
			return innerChannel.BeginRequest(message, timeout, callback, state);
		}
		/// <summary>
		/// Begins an asynchronous operation to transmit a request message to the reply-side of a request-reply message exchange.
		/// </summary>
		/// <param name="message">The request System.ServiceModel.Channels.Message to be transmitted.</param>
		/// <param name="callback">The System.AsyncCallback delegate that receives the notification of the completion of the asynchronous operation transmitting a request message.</param>
		/// <param name="state">An object, specified by the application, that contains state information associated with the asynchronous operation transmitting a request message.</param>
		/// <returns>The System.IAsyncResult that references the asynchronous message transmission.</returns>
		public IAsyncResult BeginRequest(Message message, AsyncCallback callback, object state)
		{
			return BeginRequest(message, DefaultSendTimeout, callback, state);
		}
		/// <summary>
		/// Completes an asynchronous operation to return a message-based response to a transmitted request.
		/// </summary>
		/// <param name="result">The System.IAsyncResult returned by a call to the Overload:System.ServiceModel.Channels.IInputChannel.BeginReceive method.</param>
		/// <returns>The System.ServiceModel.Channels.Message received in response to the request.</returns>
		public Message EndRequest(IAsyncResult result)
		{
			Message message = null;

			message = innerChannel.EndRequest(result);
			messageInspector.AfterReceiveReply(ref message, null);

			return message;
		}

		#region Required, unused methods
		Message IRequestChannel.Request(Message message, TimeSpan timeout)
		{
			throw new NotImplementedException();
		}
		Message IRequestChannel.Request(Message message)
		{
			throw new NotImplementedException();
		}
		#endregion

		#endregion
	}
	#endregion
}